#include "bib_Hilos.h"

extern int flagSalir;
extern struct EST_CHS CHSPlanif;
extern int grupoEspejo;

//Prototipos
char obtenerValorCHS(struct stPLANIFICADOR *planif);
char obtenerValorFinalizar(struct stPLANIFICADOR *planif);

void atencionPlanif(void *ptr) {
	struct stPLANIFICADOR *estructuraPlanif;
	char valorCHS;
	uint32_t valorEspejado;
	uint32_t valorEspejadoOK;
	char solicitudPend=0;		//0: No hay solicitud; 1: si hay solicitud pendiente
	char hora[21 + 1];
	char mensajeConsola[80];
	char finalizar=0;

	//Obtener parámetro
	estructuraPlanif = (struct stPLANIFICADOR *) ptr;

	//Informar que comenzo un hilo
	imprimirLogNumerico(DEBUG, "Un planificador comenzo su funcionamiento:",estructuraPlanif->idPlanificador);

	//Determinar si tiene el CHS correcto
	valorCHS=obtenerValorCHS(estructuraPlanif);

	while (valorCHS == 0){
		//Esperar a que tenga el valor correcto

		//Si se debe terminar, salir del hilo
		finalizar=obtenerValorFinalizar(estructuraPlanif);

		if (flagSalir == 0 || finalizar){
			cerrarSocket(estructuraPlanif->sockPlanif);
			sem_post(&estructuraPlanif->hiloFinalizado);
			return;
		}

		valorCHS=obtenerValorCHS(estructuraPlanif);
	}

	//Determinar si necesita espejar
	valorEspejado= obtenerValorEspejados(estructuraPlanif);
	valorEspejadoOK=cantSectoresPlanif(CHSPlanif);

	//Si no estan todos los sectores espejados, solicitar sectores a los otros planificadores
	if (!planificadorEspejado(estructuraPlanif)){

		//Informar que el planificador comenzo a espejarse
		tiempo(hora);
		sprintf(mensajeConsola, "%s Se inicia la sincronización del planificador", hora);
		imprimirLogNumerico(CONSOLA,mensajeConsola,estructuraPlanif->idPlanificador);

		//Solicitar sectores, de a grupos para no saturar al sistema
		uint32_t ultSectorEspejar;
		uint32_t primerSectorEspejar;
		uint32_t i;

		primerSectorEspejar=0;

		while(1){
			if (primerSectorEspejar+(grupoEspejo-1) < valorEspejadoOK)
				ultSectorEspejar=primerSectorEspejar+(grupoEspejo-1);
			else
				ultSectorEspejar=valorEspejadoOK;

			//Solicitar grupo de sectores
			for (i=primerSectorEspejar; i<=ultSectorEspejar; i++){
				//Llamar a distribuir solicitud
				if (solicitarSector(i,estructuraPlanif->idPlanificador)){
					//No se pudo espejar por un error

					imprimirLogNumerico(DEBUG,"Ocurrio un error al solicitar un sector para espejar. Id:",(int)estructuraPlanif->idPlanificador);

					//Salir del hilo
					sem_post(&estructuraPlanif->hiloFinalizado);
					cerrarSocket(estructuraPlanif->sockPlanif);
					return;
				}
			}

			//Esperar a que termine de espejar el conjunto
			while (valorEspejado<ultSectorEspejar+1){
				//Si se debe terminar, salir del hilo
				finalizar=obtenerValorFinalizar(estructuraPlanif);

				if (flagSalir == 0 || finalizar){
					sem_post(&estructuraPlanif->hiloFinalizado);
					cerrarSocket(estructuraPlanif->sockPlanif);
					return;
				}

				//Verificar si hay solicitudes pendientes para espejar
				sem_wait(&estructuraPlanif->accesoPlanif);
				if (estructuraPlanif->solicitudPendEspejar == NULL)
					solicitudPend=0;
				else
					solicitudPend=1;
				sem_post(&estructuraPlanif->accesoPlanif);

				if (solicitudPend){
					//Escribir en disco
					if (escribirEnPlanif(ESCRITURA_ESPEJO,estructuraPlanif)){
						//Se desconecto, terminar conexion

						//Si se debe terminar, salir del hilo
						sem_post(&estructuraPlanif->hiloFinalizado);
						cerrarSocket(estructuraPlanif->sockPlanif);
						return;
					}
				}

				//Obtener el nuevo valor de sectores espejados
				valorEspejado = obtenerValorEspejados(estructuraPlanif);
			}

			//Si estan todos los sectores espejados salir
			if (planificadorEspejado(estructuraPlanif)){
				break;
			}else{
				primerSectorEspejar=ultSectorEspejar+1;
			}
		}

		//Se termino de espejar, informar por consola
		tiempo(hora);
		sprintf(mensajeConsola, "%s Se completo la sincronización del planificador", hora);
		imprimirLogNumerico(CONSOLA,mensajeConsola,estructuraPlanif->idPlanificador);

		//Informar al PPD que finalizo el espejado
		if (informarFinEspejo(estructuraPlanif->sockPlanif))
			imprimirLogNumerico(WARNING,"Error al enviar el mensaje de fin de espejo al planificador:",(int)estructuraPlanif->idPlanificador);

	}

	//El planificador entro en funcionamiento normal
	finalizar=obtenerValorFinalizar(estructuraPlanif);

	while (flagSalir && (finalizar == 0)){
		//Verificar si hay solicitudes pendientes
		sem_wait(&estructuraPlanif->accesoPlanif);
		if (estructuraPlanif->solicitudPend == NULL)
			solicitudPend=0;
		else
			solicitudPend=1;

		sem_post(&estructuraPlanif->accesoPlanif);

		if (solicitudPend){
			//Escribir en disco
			if (escribirEnPlanif(ESCRITURA_NORMAL, estructuraPlanif)){
				//Se desconecto

				//Salir del hilo
				sem_post(&estructuraPlanif->hiloFinalizado);
				//Terminar conexion
				cerrarSocket(estructuraPlanif->sockPlanif);

				return;
			}
		}

		//Actualizar valor de finalizar
		finalizar=obtenerValorFinalizar(estructuraPlanif);
	}

	sem_post(&estructuraPlanif->hiloFinalizado);
	//Desconectar
	cerrarSocket(estructuraPlanif->sockPlanif);

	return;
}

char obtenerValorCHS(struct stPLANIFICADOR *planif){
	char valorCHS;

	sem_wait(&planif->accesoPlanif);
	valorCHS=planif->CHSCorrecto;
	sem_post(&planif->accesoPlanif);

	return valorCHS;
}

char obtenerValorFinalizar(struct stPLANIFICADOR *planif){
	char finalizar;

	sem_wait(&planif->accesoPlanif);
	finalizar=planif->terminarHilo;
	sem_post(&planif->accesoPlanif);

	return finalizar;
}
